package com.sgcc.nfc.lock.presentation.nfc

import android.Manifest
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.app.Activity
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.nfc.NfcAdapter
import android.nfc.Tag
import android.os.Bundle
import android.content.res.ColorStateList
import android.view.View
import android.view.animation.AccelerateDecelerateInterpolator
import android.view.animation.AnimationUtils
import android.view.HapticFeedbackConstants
import android.widget.ArrayAdapter
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import com.google.android.material.color.MaterialColors
import com.google.android.material.snackbar.Snackbar
import com.sgcc.nfc.lock.R
import com.sgcc.nfc.lock.databinding.ActivityNfcOperationBinding
import com.sgcc.nfc.lock.presentation.rooms.LocationPickerActivity
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class NfcOperationActivity : AppCompatActivity() {

    private lateinit var binding: ActivityNfcOperationBinding
    private val viewModel: NfcOperationViewModel by viewModels()
    private var nfcAdapter: NfcAdapter? = null
    private var roomItems: List<RoomOption> = emptyList()
    private val expectedLockId: String? by lazy { intent.getStringExtra(NfcOperationViewModel.EXTRA_LOCK_NFC_ID) }
    private var successAnimationRunnable: Runnable? = null
    
    private lateinit var locationManager: LocationManager
    private var isLocationUpdateRequested = false
    
    private val locationListener = object : LocationListener {
        override fun onLocationChanged(location: Location) {
            if (isLocationUpdateRequested) {
                isLocationUpdateRequested = false
                locationManager.removeUpdates(this)
                viewModel.updateLocation(location.latitude, location.longitude)
                Snackbar.make(binding.root, getString(R.string.location_success), Snackbar.LENGTH_SHORT).show()
            }
        }

        override fun onProviderEnabled(provider: String) {}
        override fun onProviderDisabled(provider: String) {
            if (isLocationUpdateRequested) {
                isLocationUpdateRequested = false
                Snackbar.make(binding.root, getString(R.string.location_failed), Snackbar.LENGTH_LONG).show()
            }
        }
    }

    private val pickLocationLauncher = registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            val data = result.data ?: return@registerForActivityResult
            val latitude = data.getDoubleExtra(LocationPickerActivity.EXTRA_LATITUDE, Double.NaN)
            val longitude = data.getDoubleExtra(LocationPickerActivity.EXTRA_LONGITUDE, Double.NaN)
            if (!latitude.isNaN() && !longitude.isNaN()) {
                viewModel.updateLocation(latitude, longitude)
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityNfcOperationBinding.inflate(layoutInflater)
        setContentView(binding.root)

        nfcAdapter = NfcAdapter.getDefaultAdapter(this)
        if (nfcAdapter == null || !(nfcAdapter?.isEnabled ?: false)) {
            Snackbar.make(binding.root, getString(R.string.nfc_prompt_title), Snackbar.LENGTH_LONG).show()
        }

        locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager

        setupToolbar()
        setupRoomDropdown()
        setupListeners()
        observeViewModel()
        
        // 处理初始的NFC intent
        handleNfcIntent(intent)
    }

    override fun onResume() {
        super.onResume()
        enableForegroundDispatch()
    }

    override fun onPause() {
        super.onPause()
        disableForegroundDispatch()
        // 清理成功动画的延迟任务，避免内存泄漏
        successAnimationRunnable?.let { 
            binding.root.removeCallbacks(it)
        }
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        handleNfcIntent(intent)
    }

    private fun observeViewModel() {
        viewModel.uiState.observe(this) { state ->
            renderMode(state.mode)
            updateRoomOptions(state)
            binding.nfcStatus.text = state.statusText
            binding.nfcProgress.isVisible = state.isProcessing || state.addLockInProgress
            binding.nfcProgress.isIndeterminate = state.chargeProgress == null
            state.chargeProgress?.let { progress ->
                binding.nfcProgress.setProgressCompat(progress, true)
            }
            updateStatusVisual(state.result)
            updateAnimationState(state.animationState, state.chargeProgress, state.result)

            binding.addLockButton.isVisible = state.showAddLockPrompt
            binding.addLockButton.isEnabled = !state.addLockInProgress
            binding.addLockButton.text = if (state.addLockInProgress) {
                getString(R.string.common_loading)
            } else {
                getString(R.string.nfc_add_lock_button)
            }

            binding.roomCard.isVisible = state.showAddLockPrompt
            binding.locationCard.isVisible = state.showAddLockPrompt
            binding.roomLayout.isEnabled = state.showAddLockPrompt
            binding.roomAutoComplete.isEnabled = state.showAddLockPrompt
            binding.pickLocationButton.isEnabled = state.showAddLockPrompt

            val locationText = if (state.showAddLockPrompt && state.latitude != null && state.longitude != null) {
                getString(R.string.nfc_location_format, state.latitude, state.longitude)
            } else {
                getString(R.string.nfc_location_placeholder)
            }
            binding.locationValue.text = locationText

            val selectedName = if (state.showAddLockPrompt) state.selectedRoom?.roomName.orEmpty() else ""
            if (state.showAddLockPrompt) {
                if (selectedName.isNotBlank() && binding.roomAutoComplete.text.toString() != selectedName) {
                    binding.roomAutoComplete.setText(selectedName, false)
                    binding.roomAutoComplete.clearFocus()
                }
            } else if (binding.roomAutoComplete.text?.isNotEmpty() == true) {
                binding.roomAutoComplete.text?.clear()
            }
            binding.roomDropdown.helperText = if (state.showAddLockPrompt) state.selectedRoom?.address else null

            if (state.message.isNullOrBlank()) {
                binding.messageText.isVisible = false
            } else {
                val messageColorAttr = if (state.result == false) {
                    com.google.android.material.R.attr.colorError
                } else {
                    com.google.android.material.R.attr.colorSecondary
                }
                binding.messageText.setTextColor(MaterialColors.getColor(binding.messageText, messageColorAttr))
                val hint = getString(R.string.nfc_message_tap_to_dismiss)
                binding.messageText.text = buildString {
                    append(state.message)
                    if (!state.message.endsWith(hint)) {
                        append("\n")
                        append(hint)
                    }
                }
                binding.messageText.isVisible = true
            }
        }
    }

    private fun updateAnimationState(animationState: NfcOperationUiState.AnimationState, chargeProgress: Int?, result: Boolean?) {
        when (animationState) {
            NfcOperationUiState.AnimationState.GUIDE -> {
                startGuideAnimation()
            }
            NfcOperationUiState.AnimationState.CHARGING -> {
                startChargingAnimation()
            }
            NfcOperationUiState.AnimationState.OPERATION -> {
                when (result) {
                    true -> startSuccessAnimation()
                    false -> startErrorAnimation()
                    null -> startOperationAnimation()
                }
            }
            NfcOperationUiState.AnimationState.SUCCESS -> {
                startSuccessAnimation()
            }
        }
    }

    private fun startGuideAnimation() {
        // 引导动画：显示引导容器，隐藏其他动画
        binding.guideAnimationContainer.isVisible = true
        binding.chargingAnimationContainer.isVisible = false
        binding.operationAnimationContainer.isVisible = false
        
        startNfcPulseAnimation()
    }

    private fun showGuideState() {
        updateNfcStatus(getString(R.string.nfc_guide_detailed))
        
        binding.guideAnimationContainer.isVisible = true
        binding.chargingAnimationContainer.isVisible = false
        binding.operationAnimationContainer.isVisible = false
        
        startNfcPulseAnimation()
    }

    private fun startNfcPulseAnimation() {
        // 清除之前的动画
        binding.nfcIcon.clearAnimation()
        
        // 启动NFC脉冲动画
        val pulseAnimation = AnimationUtils.loadAnimation(this, R.anim.nfc_pulse_animation)
        binding.nfcIcon.startAnimation(pulseAnimation)
    }

    private fun startChargingAnimation() {
        // 充电动画：显示充电容器，隐藏其他动画
        binding.guideAnimationContainer.isVisible = false
        binding.chargingAnimationContainer.isVisible = true
        binding.operationAnimationContainer.isVisible = false
        
        // 充电进度条脉冲效果
        val pulseAnimator = ObjectAnimator.ofFloat(binding.chargingProgress, "alpha", 0.5f, 1.0f).apply {
            duration = 800
            repeatCount = ValueAnimator.INFINITE
            repeatMode = ValueAnimator.REVERSE
            interpolator = AccelerateDecelerateInterpolator()
        }
        pulseAnimator.start()
    }

    private fun startOperationAnimation() {
        // 操作动画：显示操作容器，隐藏其他动画
        binding.guideAnimationContainer.isVisible = false
        binding.chargingAnimationContainer.isVisible = false
        binding.operationAnimationContainer.isVisible = true
        
        // 操作图标旋转动画
        val rotateAnimator = ObjectAnimator.ofFloat(binding.operationAnimationIcon, "rotation", 0f, 360f).apply {
            duration = 1500
            repeatCount = ValueAnimator.INFINITE
            interpolator = AccelerateDecelerateInterpolator()
        }
        rotateAnimator.start()
    }

    private fun startSuccessAnimation() {
        // 清除之前的延迟任务
        successAnimationRunnable?.let { binding.root.removeCallbacks(it) }
        
        // 触觉反馈
        binding.root.performHapticFeedback(HapticFeedbackConstants.CONFIRM)
        
        // 使用XML动画资源
        val animation = AnimationUtils.loadAnimation(this, R.anim.scale_success)
        binding.nfcStatus.startAnimation(animation)
        
        // 为NFC图标添加成功反馈
        val iconAnimation = AnimationUtils.loadAnimation(this, R.anim.scale_success)
        binding.nfcIcon.startAnimation(iconAnimation)
        
        // 成功状态持续显示5秒后重置到引导状态
        successAnimationRunnable = Runnable {
            // 只有在当前仍是成功状态时才重置
            viewModel.uiState.value?.let { state ->
                if (state.animationState == NfcOperationUiState.AnimationState.SUCCESS && state.result == true) {
                    // 通过ViewModel重置状态，而不是直接操作UI
                    viewModel.resetToGuideState()
                }
            }
        }
        binding.root.postDelayed(successAnimationRunnable!!, 5000) // 5秒后重置
    }
    
    private fun showSuccessState(successMessage: String) {
        updateNfcStatus(successMessage)
        startSuccessAnimation()
        
        // 显示成功Snackbar
        Snackbar.make(binding.root, successMessage, Snackbar.LENGTH_SHORT).show()
        
        // 5秒后自动回到引导状态
        binding.root.postDelayed({
            showGuideState()
        }, 5000)
    }

    private fun startErrorAnimation() {
        // 触觉反馈
        binding.root.performHapticFeedback(HapticFeedbackConstants.REJECT)
        
        // 使用XML动画资源
        val animation = AnimationUtils.loadAnimation(this, R.anim.shake_error)
        binding.nfcStatus.startAnimation(animation)
        
        // 为NFC图标添加错误反馈
        val iconAnimation = AnimationUtils.loadAnimation(this, R.anim.shake_error)
        binding.nfcIcon.startAnimation(iconAnimation)
    }
    
    private fun showErrorWithRetry(errorMessage: String, retryAction: (() -> Unit)? = null) {
        updateNfcStatus(errorMessage)
        startErrorAnimation()
        
        // 显示Snackbar提供重试选项
        val snackbar = Snackbar.make(binding.root, errorMessage, Snackbar.LENGTH_LONG)
        
        retryAction?.let { action ->
            snackbar.setAction(getString(R.string.common_retry)) {
                // 触觉反馈
                binding.root.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK)
                action.invoke()
            }
        }
        
        snackbar.show()
        
        // 3秒后自动回到引导状态
        binding.root.postDelayed({
            showGuideState()
        }, 3000)
    }

    private fun stopAllAnimations() {
        // 清除成功动画的延迟任务
        successAnimationRunnable?.let { 
            binding.root.removeCallbacks(it)
            successAnimationRunnable = null
        }
        
        // 清理所有动画
        binding.nfcIcon.clearAnimation()
        binding.chargingProgress.clearAnimation()
        binding.operationAnimationIcon.clearAnimation()
        binding.nfcProgress.clearAnimation()
        binding.nfcStatus.clearAnimation()
        
        // 重置所有属性
        binding.nfcIcon.alpha = 1.0f
        binding.chargingProgress.alpha = 1.0f
        binding.operationAnimationIcon.rotation = 0f
        binding.nfcProgress.alpha = 1.0f
        binding.nfcStatus.scaleX = 1.0f
        binding.nfcStatus.scaleY = 1.0f
        binding.nfcStatus.translationX = 0f
        
        // 隐藏所有动画容器
        binding.guideAnimationContainer.isVisible = false
        binding.chargingAnimationContainer.isVisible = false
        binding.operationAnimationContainer.isVisible = false
    }

    private fun renderMode(mode: NfcOperationViewModel.Mode) {
        val chipText: Int
        val subtitleText: Int
        val chipColorAttr: Int
        val chipOnColorAttr: Int
        when (mode) {
            NfcOperationViewModel.Mode.OPEN -> {
                chipText = R.string.nfc_mode_open
                subtitleText = R.string.nfc_operation_subtitle_open
                chipColorAttr = com.google.android.material.R.attr.colorPrimary
                chipOnColorAttr = com.google.android.material.R.attr.colorOnPrimary
            }
            NfcOperationViewModel.Mode.CLOSE -> {
                chipText = R.string.nfc_mode_close
                subtitleText = R.string.nfc_operation_subtitle_close
                chipColorAttr = com.google.android.material.R.attr.colorTertiary
                chipOnColorAttr = com.google.android.material.R.attr.colorOnTertiary
            }
        }
        binding.modeChip.text = getString(chipText)
        binding.headerSubtitle.text = buildString {
            append(getString(subtitleText))
            expectedLockId?.let {
                append("（标签: ")
                append(it)
                append("）")
            }
        }
        val chipColor = MaterialColors.getColor(binding.modeChip, chipColorAttr)
        val chipOnColor = MaterialColors.getColor(binding.modeChip, chipOnColorAttr)
        binding.modeChip.chipBackgroundColor = ColorStateList.valueOf(chipColor)
        binding.modeChip.setTextColor(chipOnColor)
    }

    private fun updateRoomOptions(state: NfcOperationUiState) {
        if (roomItems.map { it.id } != state.rooms.map { it.roomId }) {
            roomItems = state.rooms.map { room ->
                RoomOption(room.roomId, room.roomName ?: getString(R.string.nfc_room_hint))
            }
            val labels = roomItems.map { it.label }
            val adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, labels)
            binding.roomAutoComplete.setAdapter(adapter)
        }
    }

    private fun showRoomSelection() {
        if (binding.roomCard.visibility != View.VISIBLE) {
            binding.roomCard.visibility = View.VISIBLE
            val animation = AnimationUtils.loadAnimation(this, R.anim.fade_in)
            binding.roomCard.startAnimation(animation)
        }
        binding.roomDropdown.helperText = "请选择要操作的配电房"
    }

    private fun updateStatusVisual(result: Boolean?) {
        val statusColorAttr = when (result) {
            true -> com.google.android.material.R.attr.colorPrimary
            false -> com.google.android.material.R.attr.colorError
            else -> com.google.android.material.R.attr.colorOnSurfaceVariant
        }
        val color = MaterialColors.getColor(binding.nfcStatus, statusColorAttr)
        binding.nfcStatus.setTextColor(color)
    }

    private fun updateNfcStatus(status: String) {
        binding.nfcStatus.text = status
        
        // 根据状态更新UI样式
        when (status) {
            getString(R.string.nfc_guide_detailed) -> {
                binding.nfcStatus.setTextColor(ContextCompat.getColor(this, R.color.nfc_text_secondary))
            }
            getString(R.string.nfc_charging_detailed) -> {
                binding.nfcStatus.setTextColor(ContextCompat.getColor(this, R.color.nfc_status_info))
            }
            getString(R.string.nfc_operation_success_detailed) -> {
                binding.nfcStatus.setTextColor(ContextCompat.getColor(this, R.color.nfc_status_success))
            }
            getString(R.string.nfc_operation_error_detailed) -> {
                binding.nfcStatus.setTextColor(ContextCompat.getColor(this, R.color.nfc_status_error))
            }
            getString(R.string.nfc_no_tag_detected) -> {
                binding.nfcStatus.setTextColor(ContextCompat.getColor(this, R.color.nfc_status_warning))
            }
            getString(R.string.nfc_connection_lost) -> {
                binding.nfcStatus.setTextColor(ContextCompat.getColor(this, R.color.nfc_status_error))
            }
        }
    }

    private fun setupToolbar() {
        binding.toolbar.setNavigationOnClickListener { finish() }
    }

    private fun setupRoomDropdown() {
        binding.roomAutoComplete.setOnItemClickListener { _, _, position, _ ->
            roomItems.getOrNull(position)?.id?.let { viewModel.selectRoom(it) }
        }
        binding.roomAutoComplete.setOnClickListener { binding.roomAutoComplete.showDropDown() }
        binding.roomAutoComplete.setOnFocusChangeListener { _, hasFocus ->
            if (hasFocus) binding.roomAutoComplete.showDropDown()
        }
    }

    private fun setupListeners() {
        binding.autoLocationButton.setOnClickListener {
            requestCurrentLocation()
        }
        binding.pickLocationButton.setOnClickListener {
            val intent = LocationPickerActivity.createIntent(this, null, null)
            pickLocationLauncher.launch(intent)
        }
        binding.messageText.setOnClickListener {
            binding.messageText.visibility = View.GONE
            viewModel.clearMessage()
        }
        binding.addLockButton.setOnClickListener {
            viewModel.addPendingLock()
        }
    }

    private fun requestCurrentLocation() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) 
            != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(
                this,
                arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
                LOCATION_PERMISSION_REQUEST_CODE
            )
        } else {
            isLocationUpdateRequested = true
            try {
                locationManager.requestLocationUpdates(
                    LocationManager.GPS_PROVIDER,
                    0L,
                    0f,
                    locationListener
                )
            } catch (e: SecurityException) {
                isLocationUpdateRequested = false
                Snackbar.make(binding.root, getString(R.string.location_failed), Snackbar.LENGTH_LONG).show()
            }
        }
    }

    private fun enableForegroundDispatch() {
        val adapter = nfcAdapter ?: return
        val intent = Intent(this, javaClass).addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING)
        val pendingIntent = PendingIntent.getActivity(
            this,
            0,
            intent,
            PendingIntent.FLAG_MUTABLE
        )
        adapter.enableForegroundDispatch(this, pendingIntent, null, null)
    }

    private fun disableForegroundDispatch() {
        nfcAdapter?.disableForegroundDispatch(this)
    }
    
    private fun handleNfcIntent(intent: Intent?) {
        if (intent == null) return
        
        val action = intent.action
        if (action == NfcAdapter.ACTION_NDEF_DISCOVERED || 
            action == NfcAdapter.ACTION_TAG_DISCOVERED || 
            action == NfcAdapter.ACTION_TECH_DISCOVERED) {
            
            val tag: Tag? = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
            tag?.let { viewModel.onTagDetected(it) }
        }
    }
    
    companion object {
        private const val LOCATION_PERMISSION_REQUEST_CODE = 1001
        
        fun createIntent(
            context: Context,
            lockNfcId: String? = null,
            roomId: Long? = null,
            mode: NfcOperationViewModel.Mode = NfcOperationViewModel.Mode.OPEN,
            password: String = "123456"
        ): Intent {
            return Intent(context, NfcOperationActivity::class.java).apply {
                lockNfcId?.let { putExtra(NfcOperationViewModel.EXTRA_LOCK_NFC_ID, it) }
                roomId?.let { putExtra(NfcOperationViewModel.EXTRA_ROOM_ID, it) }
                putExtra(NfcOperationViewModel.EXTRA_ACTION, mode.name)
                putExtra(NfcOperationViewModel.EXTRA_PASSWORD, password)
            }
        }
    }

    private data class RoomOption(val id: Long?, val label: String)
}
